<?php
/**
 * Desc:
 * User: 叶力铭
 */

class FaceID
{
    const version = '1.0.0';

    //AccessToken key
    const FaceAccessTokenKey = 'FaceAccessToken';
    //SignTicket key
    const SignTicketKey = 'SignTicket';

    static private $appId = 'IDAMTqA6';
    static private $secretId = 'egVdYwwB424xhVHtH31rSz4JFlkK0WkNe1NUCwTCqFVeLTzNO7f2EEprA2ubLPJf';
    static private $license = 'HcGC6Phoeo69zZMS/s5EMYtdsNkb1HyHRTGKsGJ7Ytq9HzOXEa+X7Btu9wd2lFBP9RkaEMwHiNXY49HlcwudF7XzjWtxn9UbJskwAROsP/mA29DWL1K0X5heWnAiiOqwC1mBycMzsRHcKA20hpn2LUle6hfS0eq06+Fy/vAoRLcUf+j/fIis/G8QVHfe2WGtC5lqbQlp4O5tOQSmXE+JEX5JwOXR1LuA4zhAsczQOy0E6HtR2jmBPZ4WIGCXc+tdaLi+t3kcZB8lfXYY9NHQPm1PFDHI17Tct4VWsyaGPoJ8Guu+2+G9rdINiyuywucgYnN2Xb58Yj5RBbevWS4xLw==';

    //默认请求头
    static private $headers = ['Content-type:application/json;charset=utf-8'];

    //错误信息
    static protected $error = '';
    //错误码
    static protected $code = '';
    //比对源照片类型，1：水纹正脸照 2：高清正脸照
    static private $sourcePhotoType	= 1;

    public function __construct()
    {

    }

    /**
     * Desc: 获取错误信息
     * User: 叶力铭
     */
    static public function getErr()
    {
        return self::$error;
    }

    /**
     * Desc: 设置错误信息
     * User: 叶力铭
     * @param $msg
     */
    static private function setErr($msg)
    {
        self::$error = $msg;
    }

    /**
     * Desc: 获取错误信息
     * User: 叶力铭
     */
    static public function getCode()
    {
        return self::$code;
    }

    /**
     * Desc: 设置错误信息
     * User: 叶力铭
     * @param $code
     */
    static private function setCode($code)
    {
        self::$code = $code;
    }

    /**
     * Desc: 获取access_token
     * User: 叶力铭
     * @return bool|mixed|string
     * @throws Exception
     */
    static private function getAccessToken()
    {
        $url = 'https://idasc.webank.com/api/oauth2/access_token';

        $redis = self::getCacheDrive();

        $accessToken = $redis->get(self::FaceAccessTokenKey);

        if (!$accessToken && 0 !== $accessToken && '0' !== $accessToken){

            $data['app_id'] = self::$appId;
            $data['secret'] = self::$secretId;
            $data['grant_type'] = 'client_credential';
            $data['version'] = self::version;

            $url = $url.'?'.http_build_query($data);

            list($bool, $ret) = self::httpGet($url, self::$headers);
            if ($bool && 0 == $ret['code']){
                $accessToken = $ret['access_token'];
                $redis->set(self::FaceAccessTokenKey, $accessToken, 7000);
            }else{
                self::setErr($ret['msg']);
                self::setCode($ret['code']);
                $accessToken = false;
            }
        }

        return $accessToken;

    }

    /**
     * Desc: 获取ticket
     * User: 叶力铭
     * @param $userId
     * @return bool|mixed
     * @throws Exception
     */
    static private function getTicket($userId)
    {
        $url = 'https://idasc.webank.com/api/oauth2/api_ticket';
        $accessToken = self::getAccessToken();

        if (false === $accessToken){
            return false;
        }
        $data['app_id'] = self::$appId;
        $data['access_token'] = $accessToken;
        $data['type'] = 'NONCE';
        $data['version'] = self::version;
        $data['user_id'] = $userId;

        $url = $url.'?'.http_build_query($data);

        list($bool, $ret) = self::httpGet($url, self::$headers);

        if ($bool && 0 == $ret['code']){

            return $ret['tickets'][0]['value'];
        }else{
            self::setErr($ret['msg']);
            self::setCode($ret['code']);
            return false;
        }
    }

    /**
     * Desc: 获取签名
     * User: 叶力铭
     * @param $userId
     * @param $nonceStr
     * @return bool|string
     * @throws Exception
     */
    static private function getSing($userId, $nonceStr)
    {
        $ticket = self::getTicket($userId);
        if (false === $ticket){
            return false;
        }
        $data['wbappid'] = self::$appId;
        $data['userId'] = $userId;
        $data['nonceStr'] = $nonceStr;
        $data['version'] = self::version;
        $data['ticket'] = $ticket;

        sort($data);
        return sha1(join('',$data));
    }

    /**
     * Desc: 获取faceId
     * User: 叶力铭
     * @param $orderNo
     * @param $name
     * @param $idNo
     * @param $userId
     * @param $sign
     * @return bool|mixed
     */
    static private function getFaceId($orderNo, $name, $idNo, $userId, $sign)
    {
        $url = 'https://idasc.webank.com/api/server/getfaceid';

        $data['webankAppId'] = self::$appId;
        $data['orderNo'] = $orderNo;
        $data['name'] = $name;
        $data['idNo'] = $idNo;
        $data['userId'] = $userId;
        $data['sourcePhotoType	'] = self::$sourcePhotoType;
        $data['version'] = self::version;
        $data['sign'] = $sign;

        list($bool, $ret) = self::httpPost($url, json_encode($data), self::$headers);
        if ($bool && 0 == $ret['code']){
            return $ret['result']['faceId'];
        }else{
            self::setErr($ret['msg']);
            self::setCode($ret['code']);
            return false;
        }
    }

    /**
     * Desc: 生成人脸核身配置信息
     * User: 叶力铭
     * @param $userId
     * @param $orderNo
     * @param $name
     * @param $idNo
     * @return bool
     * @throws Exception
     */
    static public function getFaceConfig($userId, $orderNo, $name, $idNo)
    {
        $nonceStr = self::createNonce();
        $sign = self::getSing($userId,$nonceStr);
        $faceId = self::getFaceId($orderNo,$name,$idNo, $userId,$sign);

        if (false === $faceId){
            return false;
        }

        $data['faceId'] = $faceId;
        $data['orderNo'] = $orderNo;
        $data['appId'] = self::$appId;
        $data['version'] = self::version;
        $data['nonceStr'] = $nonceStr;
        $data['userId'] = $userId;
        $data['sign'] = $sign;
        $data['licence'] = self::$license;

        return $data;
    }

    /**
     * Desc: 获取SignTicket
     * User: 叶力铭
     * @return bool|mixed|string
     * @throws Exception
     */
    static private function getSignTicket()
    {
        $url = 'https://idasc.webank.com/api/oauth2/api_ticket';

        $redis = self::getCacheDrive();

        $signTicket = $redis->get(self::SignTicketKey);

        if (!$signTicket && 0 !== $signTicket && '0' !== $signTicket){
            $accessToken = self::getAccessToken();

            if (false === $accessToken){
                return false;
            }

            $data['app_id'] = self::$appId;
            $data['access_token'] = $accessToken;
            $data['type'] = 'SIGN';
            $data['version'] = self::version;

            $url = $url.'?'.http_build_query($data);

            list($bool, $ret) = self::httpGet($url, self::$headers);

            if ($bool && 0 == $ret['code']){
                $signTicket = $ret['tickets'][0]['value'];
                $redis->set(self::SignTicketKey, $signTicket, 3000);
            }else{
                self::setErr($ret['msg']);
                self::setCode($ret['code']);
                return false;
            }
        }

        return $signTicket;

    }

    /**
     * Desc: 获取结果验证sign
     * User: 叶力铭
     * @param $orderNo
     * @param $nonceStr
     * @return bool|string
     * @throws Exception
     */
    static private function getVerifySing($orderNo, $nonceStr)
    {
        $ticket = self::getSignTicket();

        if (false === $ticket){
            return false;
        }

        $data['wbappid'] = self::$appId;
        $data['order_no'] = $orderNo;
        $data['nonceStr'] = $nonceStr;
        $data['version'] = self::version;
        $data['ticket'] = $ticket;

        sort($data);
        return sha1(join('',$data));
    }

    /**
     * Desc: 获取验证结果
     * User: 叶力铭
     * @param $orderNo
     * @return bool|mixed
     * @throws Exception
     */
    static public function verifyFace($orderNo)
    {
        $url = 'https://idasc.webank.com/api/server/sync';

        $nonceStr = self::createNonce();
        $verifySing = self::getVerifySing($orderNo, $nonceStr);

        $data['app_id'] = self::$appId;
        $data['version'] = self::version;
        $data['nonce'] = $nonceStr;
        $data['order_no'] = $orderNo;
        $data['sign'] = $verifySing;
        $data['get_file'] = '';

        $url = $url.'?'.http_build_query($data);

        list($bool, $ret) = self::httpGet($url, self::$headers);

        if ($bool && 0 == $ret['code']){

            return $ret['result'];
        }else{
            self::setErr($ret['msg']);
            self::setCode($ret['code']);
            return false;
        }

    }

    /**
     * Desc: Redis connection
     * User: 叶力铭
     * @return Redis|null
     * @throws Exception
     */
    static private function getCacheDrive()
    {
        $CI = &get_instance();
        $CI->load->library('BufferCache');
        return BufferCache::getCacheApp();
    }

    /**
     * Desc: 生成随机字符串
     * User: 叶力铭
     * @param int $length
     * @return string
     */
    static private function createNonce($length = 32)
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++){
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    /**
     * Desc: get请求
     * User: 叶力铭
     * @param $url
     * @param array $headers
     * @param int $second
     * @return array
     */
    static private function httpGet($url, $headers = [], $second = 60)
    {
        $ch = curl_init();

        if (!empty($headers)){
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        }
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        //超时时间
        curl_setopt($ch, CURLOPT_TIMEOUT,$second);
        //运行curl
        $data = curl_exec($ch);
        $dataArr = json_decode($data, true);
        if ($dataArr) {
            curl_close($ch);
            return [true, $dataArr];
        }else{
            $error = curl_errno($ch);
            curl_close($ch);
            return [false, $error];
        }
    }

    /**
     * Desc: post请求
     * User: 叶力铭
     * @param $url
     * @param $sendData
     * @param array $headers
     * @param int $second
     * @return array
     */
    static private function httpPost($url, $sendData, $headers = [], $second = 60)
    {
        $ch = curl_init();

        if (!empty($headers)){
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        }
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        //超时时间
        curl_setopt($ch, CURLOPT_TIMEOUT,$second);
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $sendData);
        //运行curl
        $data = curl_exec($ch);

        $dataArr = json_decode($data, true);
        if ($dataArr) {
            curl_close($ch);
            return [true, $dataArr];
        }else{
            $error = curl_errno($ch);
            curl_close($ch);
            return [false, $error];
        }
    }

}